///-----------------------------------------------------------------------------
/// Filename: Controller.cs
///
/// Description: 
///  Contains the classes used in the basic MVC controller stage. The controller
///  itself is an XML aggregator conroller meaning it builds up the Model from
///  a number of XML documents.
///
/// History:
/// 24 Jan 2004	Aaron Clauson	Created.
/// 04 Sep 2004 Aaron Clauson	Added the no cache directive to the HTTP response.
/// 09 Sep 2004	Aaron Clauson	Added a more detailed exception message when a
///								controller class cannot be instantiated.
///	08 Nov 2004	Aaron Clauson	Added an implicit load of a system.xml file to
///								the models. Used for system wide settings required
///								by view stages such as web paths.
///	28 Nov 2004	Aaron Clauson	Added pagepath setting to model to indicate whether 
///								SSL pages should use the secure path or not.
///
/// License: 
/// Public Domain.
///-----------------------------------------------------------------------------

using System;
using System.Collections;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Xml;
using MaverickLite.Config;
using MaverickLite.Model;
using MaverickLite.View;
using log4net;

namespace MaverickLite.Controller
{
	public class ControllerProduct
	{
		protected const string CONTROLLER_PARAM_KEY = "param";
		protected const string CONTROLLER_PARAM_NAME_ATTRIBUTE = "name";
		protected const string CONTROLLER_PARAM_VALUE_ATTRIBUTE = "value";
		protected const string MODEL_NODE_NAME = "model";	
		protected const string MODEL_PATH_NODE_NAME = "path";	
		protected const string VIEW_NODE_NAME = "view";
		protected const string VIEW_NAME_ATTRIBUTE = "name";
		protected const string CONTENTTYPE_PARAMETER_NAME = "contenttype";
		
		protected ILog logger = MavAppState.logger;

		protected IDictionary ViewMap;
		protected RequestState MavRequestState;
		protected SessionState MavSessionState;

		protected string m_pagePathKey = MavAppState.PAGE_PATH_KEY;
		protected string m_securePathKey = MavAppState.SECURE_PAGE_PATH;
		protected string m_webAppPathKey = MavAppState.WEB_APP_PATH;

		protected string m_pagePath = null;		// These paths will always be added to the model and available for
		protected string m_webAppPath = null;	// use in the View stages.
		protected string m_securePath = null;

		protected static XmlDocument m_systemDataNode = MavAppState.SystemSettingsDom;		// XML node that contains a node with common system settings for the view stage (web paths etc.)

		protected static string m_physicalApplicationPath = MavAppState.PhysicalApplicationPath;
		protected XmlElement InitialParameters = null;			// Keeps a record of the initial parameters for use by derived controllers.
		protected Hashtable SimpleParameters = new Hashtable();	// Xml nodes with no children will be placed as name value pairs into this hashtable.
		protected string m_view;

		protected static Hashtable m_specialParameters = MavAppState.SpecialParameters;	// Special parameters for model, e.g. ${path}.

		public virtual void Go(HttpContext context)
		{
			// Set the special pagepath parameter based on whether the request was made over SSL or not.
			if(m_specialParameters[m_securePathKey] != null)
			{
				m_securePath = m_specialParameters[m_securePathKey].ToString();
			}
			
			if(m_specialParameters[m_webAppPathKey] != null)
			{
				m_webAppPath = m_specialParameters[m_webAppPathKey].ToString();
			}

			if(context.Request.IsSecureConnection)
			{
				m_pagePath = m_securePath;
				m_specialParameters[m_pagePathKey] = m_securePath;
			}
			else
			{
				m_pagePath = m_webAppPath;
				m_specialParameters[m_pagePathKey] = m_webAppPath;
			}
			
			// Initialise wrapper objects for HTTP request and session access.
			MavRequestState = new RequestState(context);
			MavSessionState = new SessionState(context);
		}
	}

	public class ControllerFactory
	{
		private const string CONTROLLER_NODE_NAME = "controller";
		private const string CLASS_ATTRIBUTE_NAME = "class";

		private static ILog logger = MavAppState.logger;

		public static ControllerProduct CreateController(XmlElement commandNode)
		{
			ControllerProduct controller = null;
			XmlNode controllerNode = commandNode.SelectSingleNode(CONTROLLER_NODE_NAME);

			if(controllerNode != null)
			{
				// If the controller element has a class attribute use it to create the controller object.
				string controllerClass = null;
				XmlNode classNode = controllerNode.Attributes.GetNamedItem(CLASS_ATTRIBUTE_NAME);
				if(classNode != null)
				{
					controllerClass = classNode.Value;
				}
				
				// Create the Controller object.
				if(controllerClass != null)
				{
					try 
					{
						Type controllerType = Type.GetType(controllerClass);
						controller = (ControllerProduct)Activator.CreateInstance(controllerType, new object[] {controllerNode});
						//logger.Debug("A controller of type, " + controllerClass + ", was created.");
					} 
					catch(ArgumentNullException nullExcp)
					{
						logger.Error("ArgumentNullException attempting to create a controller instance of type, " + controllerClass + ". " + nullExcp.Message);
						throw new ApplicationException("Unable to create a controller of type " + controllerClass + ". Check that the assembly is available and the class exists.");
					}
					catch(Exception excp) 
					{
						logger.Error("Exception attempting to create a controller instance of type, " + controllerClass + ". " + excp.Message);
						throw excp;
					}
				}
				else
				{	
					controller = new XmlController((XmlElement)controllerNode);
				}
			}

			return controller;
		}
	}
	
}
